﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Multithreading多线程
{
    /// <summary>
    /// ThreadPool线程池2.0 、是一个享元模式
    /// 在我们1.0使用Thread给我们提供了太多API了，会是一把双刃剑
    /// ThreadPool就对Thread进行可很多限制。
    /// 我们之前可以无限的使用线程，使用不当就会GG
    /// ThreadPool对我们线程进行了一个很好的管理
    /// 重用线程、避免重复的销毁和创建
    /// </summary>
    public class MyThreadPoolDoem
    {
        /// <summary>
        /// ThreadPool的使用
        /// workerThreads 　CLR线程池分为工作者线程(workerThreads)
        /// completionPortThreads I/O线程(completionPortThreads)
        /// </summary>
        public static void Show()
        {
            //使用线程
            ThreadPool.QueueUserWorkItem((x) => Running());
            ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
            Console.WriteLine($"没有设置线程数之前 workerThreads:{workerThreads}  completionPortThreads:{completionPortThreads}");
            //设置最大的线程数
            ThreadPool.SetMaxThreads(16, 16);
            //设置最小的线程数
            ThreadPool.SetMinThreads(8, 8);
            ThreadPool.GetAvailableThreads(out int workerThreads1, out int completionPortThreads1);
            Console.WriteLine($"设置最大的线程数之后 workerThreads:{workerThreads1}  completionPortThreads:{completionPortThreads1}");
            Console.ReadLine();
        }

        /// <summary>
        /// ThreadPool 线程等待
        ///类  包含了一个bool属性
        ///false--WaitOne等待--Set--true--WaitOne直接过去
        ///true--WaitOne直接过去--ReSet--false--WaitOne等待
        ///https://www.cnblogs.com/howtrace/p/11362284.html
        /// </summary>
        public static void Show1()
        {
            //设置最大的线程数
            ThreadPool.SetMaxThreads(16, 16);
            //设置最小的线程数
            ThreadPool.SetMinThreads(8, 8);
            //设置false使用WaitOne()会直接堵塞线程，不会释放 、Set()设置为true
            ManualResetEvent manualResetEvent = new ManualResetEvent(false);
            //设置false使用WaitOne()会直接堵塞线程，不会释放 、Set()设置为true
            AutoResetEvent autoResetEvent = new AutoResetEvent(false);
            //上面两种方法都是可以拦截线程，都是继承EventWaitHandle 接口
            //就都具有Reset() //红灯 设置为false导致线程等待
            //Set() //绿灯 设置为true 启动线程继续执行
            //WaitOne() // 等待信号 会根据我们线程状态执行，为true不需要等待直接执行
            //反之为false会等待线程状态为true才会执行

            //不同点 ManualResetEvent AutoResetEvent
            //ManualResetEvent 在·使用Set()的时候会所有处理 WaitOne 状态线程均继续执行。
            //AutoResetEvent 在使用Set()的时候会执行一个线程其他的线程继续等待执行。

            for (int i = 0; i < 20; i++)
            {
                var k = i;
                ThreadPool.QueueUserWorkItem(x =>
                {
                    Console.WriteLine(k);
                    if (k < 18)
                    {
                        //等待线程，但是上面我们只开了16个线程，结果我18个线程全部等待
                        //导致了死锁
                        manualResetEvent.WaitOne();
                    }
                    else
                    {
                        //恢复执行状态
                        manualResetEvent.Set();
                    }
                });
                if (manualResetEvent.WaitOne())
                {
                    Console.WriteLine("没有死锁、、、");
                }
                Console.WriteLine("等着QueueUserWorkItem完成后才执行");
            }
            Console.ReadLine();
        }

        /// <summary>
        /// 一个执行需要长时间的任务
        /// </summary>
        static void Running(int s)
        {
            Console.WriteLine("**********************************");
            Console.WriteLine("执行开始啦" + s);
            Console.WriteLine("获取当前执行的线程ID：" + Thread.CurrentThread.ManagedThreadId.ToString());
            var j = 0;
            for (int i = 0; i < 1000000000; i++)
            {
                j++;
            }
            Console.WriteLine("执行结束啦" + s);
        }

        /// <summary>
        /// 一个执行需要长时间的任务
        /// </summary>
        static int Running()
        {
            Console.WriteLine("**********************************");
            Console.WriteLine("执行开始啦");
            Console.WriteLine("获取当前执行的线程ID：" + Thread.CurrentThread.ManagedThreadId.ToString());
            var j = 0;
            for (int i = 0; i < 1000000000; i++)
            {
                j++;
            }
            Console.WriteLine("执行结束啦");
            return j;
        }
    }
}
